<script setup lang="ts">
import { h, onBeforeMount, type PropType, provide, ref, type VNode, watch } from "vue";
import type { RenderNavigationInfo, SimpleNavigationContext, SimpleNavigationInfo } from "./simple-navigation-helper";
import SimpleNavigationItem from "./simple-navigation-item.vue";
import type { ComponentType } from "@/framework/vue/types";
import { noop } from "@/framework/util/warning";
import Strings from "@/framework/util/strings";
import { isNotNull } from "@/framework/util/validates";

const props = defineProps({
  navigations: { type: Array as PropType<SimpleNavigationInfo[]>, required: true },
});
const emits = defineEmits({
  "navigation-changed": (navigations: RenderNavigationInfo[]) => isNotNull(navigations),
});

const renderNavigations = ref<RenderNavigationInfo[]>([]);
watch(renderNavigations, value => emits("navigation-changed", value), { deep: true });

const getRenderNavigationInfo = async (path: string): Promise<RenderNavigationInfo> => {
  const nav = props.navigations!.find(it => it.path === path);
  let vnode: VNode;
  if (!nav) {
    vnode = h("span", { style: { color: "red" } }, `Not found: ${path}`);
  } else {
    if (typeof nav.component === "function") {
      try {
        const resp = await (nav.component as Function)();
        vnode = h(resp.default as ComponentType);
      } catch (e: any) {
        vnode = h("span", { style: { color: "red" } }, `Component error : ${e.message}`);
        console.error(e);
      }
    } else {
      vnode = h(nav.component);
    }
  }
  return {
    key: `${path}_${Strings.randomStr()}`,
    path,
    name: nav?.name,
    component: vnode,
  };
};

const ctx: SimpleNavigationContext = {
  push: async path => {
    renderNavigations.value.push(await getRenderNavigationInfo(path));
  },
  replace: async path => {
    renderNavigations.value.splice(renderNavigations.value.length - 1, 1, await getRenderNavigationInfo(path));
  },
  pop: count => {
    count = Math.min(count, renderNavigations.value.length - 1);
    if (count > 0) {
      renderNavigations.value.splice(renderNavigations.value.length - count, count);
    }
  },
  popToTop: () => {
    if (renderNavigations.value.length > 1) {
      renderNavigations.value.splice(1, renderNavigations.value.length - 1);
    }
  },
  back: () => {
    if (renderNavigations.value.length > 1) {
      renderNavigations.value.splice(renderNavigations.value.length - 1, 1);
    }
  },
};

provide("simple-navigation-context", ctx);
defineExpose(ctx);

onBeforeMount(() => {
  if (renderNavigations.value.length === 0) {
    ctx.push(props.navigations![0].path).then(noop);
  }
});

const onMouseDown = (e: MouseEvent) => {
  if (e.button === 3) {
    // 鼠标侧边键快捷返回
    ctx.back();
  }
};
</script>

<template>
  <div class="simple-navigation" @mousedown="onMouseDown">
    <simple-navigation-item v-for="(item, index) in renderNavigations" :key="item.key" :visible="index === renderNavigations.length - 1">
      <component :is="item.component" v-show="index === renderNavigations.length - 1" />
    </simple-navigation-item>
  </div>
</template>

<style lang="less">
.simple-navigation {
  height: 100%;
  width: 100%;
  overflow: auto;
}
</style>
